'''
Created on 2010-2-12

@author: summit
'''

class Array(object):
    '''
    Extending Python Lists - An Array Class
    While the Python programming language does indeed provide built-in support 
    for lists, that support is not without its shortcomings: For example, the 
    first (or leftmost) index of a list is always zero (or -n) and the rightmost
    index of a list is always n-1 (or -1). However, in certain applications, it
    is desireable to index list elements starting with a non-zero base index. 
    Another issue arise from the fact that negative indices are allowed. In 
    many applications, only non-negative indices are required and an attempt 
    to use a negative index is evidence of a programming error. Because Python
    allows negative indices, such errors are not detected at run time and may
    lead to incorrect program execution. 
    '''


    def __init__(self, length=0, baseIndex=0):
        '''
        Constructor
        '''
        assert length >= 0
        self._data = [ None for i in xrange(length) ]
        self._baseIndex = baseIndex
    
    def __copy__(self):
        '''
        This method provides a way to create a copy of a given array. 
        Specifically, the __copy__ method creates a shallow copy    
        A shallow copy creates a copy of the Array object but does not 
        copy the objects contained in the array. 
        '''
        result = Array(len(self._data))
        for i, datum in enumerate(self._data):
            result._data[i] = datum
        result._baseIndex = self._baseIndex
        return result
    
    def getOffset(self, index):
        offset = index - self._baseIndex
        if offset<0 or offset>=len(self._data):
            raise IndexError
        return offset
    
    def __getitem__(self, index):
        return self._data[self.getOffset(index)]
    
    def __setitem__(self, index, value):
        self._data[self.getOffset(index)]=value
        
    def getData(self):
        return self._data
    
    data = property(fget=lambda self: self.getData())
    
    def getBaseIndex(self):
        return self._baseIndex
    
    def setBaseIndex(self, baseIndex):
        self._baseIndex = baseIndex
        
    baseIndex = property(fget=lambda self: self.getBaseIndex(),
                         fset=lambda self, value: self.setBaseIndex(value))
    
    def __len__(self):
        return len(self._data)
    
    def setLength(self, value):
        if len(self._data)!=value:
            newData = [None for i in xrange(value)]
            m = min(len(self._data), value)
            for i in xrange(m):
                newData[i]=self._data[i]
            self._data = newData
    
    length = property(fget=lambda self: self.__len__(), 
                      fset=lambda self, value: self.setLength(value))